package com.android.kotlincoroutinemvvmdemo.hook

import android.content.Context
import android.util.Log
import android.view.View
import android.view.View.OnClickListener
import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method
import java.lang.reflect.Proxy

object HookListener {
    /*
     * Hook的理解:一种用于改变API执行结果的技术
     * Hook点:选择容易找到并且不易发生变化的对象.比如静态变量和单例.
     * Hook思路:将自己的代码逻辑替换成干涉执行的逻辑,通常要用到反射和动态代理,需要对SDK源码很熟悉,能找到函数入口.
     * 具体步骤:
     *    一:确认需要hook操作对象(A a)
     *    二:获取hook干涉执行逻辑的拥有者(B b)
     *    三:获取需要hook的操作对象(A a)
     *    四:创建要hook对象的代理对象,并加入自己的逻辑代码
     *    五:将创建的hook对象的代理对象,在B中对hook对象进行替换
     * */
    private const val TAG = "HookListener"

    fun registerListener(context: Context, view: View) {
        //反射执行View类的getListenerInfo()方法,拿到v的mListenerInfo对象,这个对象就是点击事件的持有者.
        try {
            val method = View::class.java.getDeclaredMethod("getListenerInfo")
            method.isAccessible = true
            //拿到mListenerInfo,也就是点击事件的持有者
            val listenerInfo = method.invoke(view)

            //找到mListenerInfo持有的点击事件对象
            val listenerInfoClazz = Class.forName("android.view.View\$ListenerInfo")
            val field = listenerInfoClazz.getDeclaredField("mOnClickListener")
            val onClickListenerInstance = field.get(listenerInfo)

            //动态代理获取View.OnClickListener即mOnClickListener对象
            val proxyClickListener =
                Proxy.newProxyInstance(
                    context.javaClass.classLoader,
                    arrayOf(View.OnClickListener::class.java),
                    object : InvocationHandler {
                        private var clickCount = 0
                        override fun invoke(
                            proxy: Any?,
                            method: Method?,
                            args: Array<out Any>?
                        ): Any? {
                            clickCount++
                            Log.d(TAG, "HookListener--${clickCount}")
                            return method?.invoke(onClickListenerInstance, *args.orEmpty())
                        }
            })

            //创建类对象
            //val proxyClickListener = ProxyClickListener(onClickListenerInstance as? OnClickListener)

            //替换持有者拥有的点击事件代理类
            field.set(listenerInfo, proxyClickListener)
        } catch (ex: Exception) {
            ex.printStackTrace()
        }
    }

    class ProxyClickListener(clickListener: OnClickListener?) : View.OnClickListener {
        private var clickCount = 0
        private val mOnClickListener = clickListener
        override fun onClick(view: View?) {
            clickCount++
            Log.d(TAG, "HookListener--${clickCount}")
            mOnClickListener?.onClick(view)
        }
    }

}